home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
admin
/
linuxcon.000
/
linuxcon
/
linuxconf-1.6
/
mailconf
/
complex.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-22
|
8KB
|
333 lines
/* #Specification: mailconf / complex user routing / strategy
The /etc/aliases mecanims allows one to redirect email to another user
once it is knows that the email is for this user on this system.
The /var/lib/mailertable mecanism allows one to redirect email for
a complete domain to another email server.
The complex user routing is a special case allowing you to redirect
email based on user name and domain name. This was created for
ISP hosting virtual domain both for WWW and email. This mecanism can
differentiate between info@virtual1.com and info@virtual2.com.
This capability is achieved by generating sendmail.cf rules directly.
*/
#include <stdio.h>
#include <string.h>
#include "mailconf.h"
#include "internal.h"
#include "mailconf.m"
static MAILCONF_HELP_FILE help_cplx ("complex");
PUBLIC COMPLEX_ROUTE::COMPLEX_ROUTE(
const char *buf)
{
SSTRING act;
buf = str_extract (buf,act);
active = act.getval();
buf = str_extract (buf,from);
buf = str_extract (buf,to);
buf = str_extract (buf,new_from);
buf = str_extract (buf,new_to);
buf = str_extract (buf,router);
buf = str_extract (buf,mailer);
buf = str_extract (buf,comment);
}
PUBLIC COMPLEX_ROUTE::COMPLEX_ROUTE()
{
active = 1;
mailer.setfrom ("esmtp");
}
/*
Edit one rule, return 0 if the edit was successful
return 1 if this record should be deleted.
*/
PUBLIC int COMPLEX_ROUTE::edit()
{
int ret = -1;
DIALOG dia;
dia.newf_chk ("",active,MSG_U(F_CPLXACTIVE,"This rule is active"));
//dia.newf_str (MSG_U(F_FROM,"from (opt)"),from);
dia.newf_str (MSG_U(F_TO,"to"),to);
//dia.newf_str (MSG_U(F_NEWFROM,"new from (opt)"),new_from);
dia.newf_str (MSG_U(F_NEWTO,"rewriten to"),new_to);
dia.newf_str (MSG_U(F_ROUTER,"Forward to server(opt)"),router);
FIELD_COMBO *comb = dia.newf_combo (MSG_R(F_MAILER),mailer);
dia.newf_str (MSG_U(F_COMMENT,"Comment"),comment);
dia.delwhat (MSG_U(F_DELCPLX,"delete the record"));
basic_setmailer (comb);
int nof = 0;
while (1){
char buf[100];
if (to.is_empty()){
strcpy (buf,MSG_U(T_NEWCOMPLEXROUTE,"New complex route"));
}else{
sprintf (buf,MSG_U(T_COMPLEXROUTE,"complex routing for %s")
,to.get());
}
MENU_STATUS code = dia.edit (buf
,MSG_U(I_COMPLEXROUTE
,"You are allowed to intercept email going to a user\n"
"and redirect this to a new mail server,\n"
"using a different protocol.\n"
"In the process, you can rewrite the TO field\n"
"and even the from field\n")
,help_cplx
,nof
,MENUBUT_DEL|MENUBUT_ACCEPT|MENUBUT_CANCEL);
if (code == MENU_CANCEL || code == MENU_ESCAPE){
dia.restore();
break;
}else if (code == MENU_DEL){
ret = 1;
break;
}else{
char status[2000];
if (rule0(NULL,status)==-1){
xconf_error ("%s",status);
}else{
ret = 0;
break;
}
}
}
return ret;
}
static const char CPLXMAIL[]="cplxmail";
static const char CASES[]="cases";
PUBLIC COMPLEX_ROUTES::COMPLEX_ROUTES()
{
SSTRINGS strs;
int nb = linuxconf_getall (CPLXMAIL,CASES,strs,0);
for (int i=0; i<nb; i++){
add (new COMPLEX_ROUTE(strs.getitem(i)->get()));
}
rstmodified();
}
PUBLIC COMPLEX_ROUTE *COMPLEX_ROUTES::getitem(int no)
{
return (COMPLEX_ROUTE*)ARRAY::getitem(no);
}
PUBLIC void COMPLEX_ROUTES::save()
{
linuxconf_removeall (CPLXMAIL,CASES);
int n = getnb();
for (int i=0; i<n; i++){
COMPLEX_ROUTE *c = getitem(i);
char buf[1000];
sprintf (buf,"%d \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\""
,c->active
,c->from.get(),c->to.get()
,c->new_from.get(),c->new_to.get()
,c->router.get(),c->mailer.get()
,c->comment.get());
linuxconf_add (CPLXMAIL,CASES,buf);
}
if (linuxconf_save()!=-1){
rstmodified();
}
}
static int cmp_by_to (const ARRAY_OBJ *p1, const ARRAY_OBJ *p2)
{
COMPLEX_ROUTE *r1 = (COMPLEX_ROUTE*)p1;
COMPLEX_ROUTE *r2 = (COMPLEX_ROUTE*)p2;
int ret = r1->to.cmp(r2->to);
if (ret == 0) ret = r1->from.cmp(r2->from);
return ret;
}
PUBLIC int COMPLEX_ROUTES::edit()
{
int ret = 0;
int nof = 0;
while (1){
sort(cmp_by_to);
DIALOG dia;
int n = getnb();
for (int i=0; i<n; i++){
COMPLEX_ROUTE *cp = getitem(i);
dia.new_menuitem (cp->to,cp->new_to);
}
dia.addwhat (MSG_U(T_ADDCPLX,"A complex routing rule"));
MENU_STATUS code = dia.editmenu (MSG_U(T_COMPLEXROUTES,"Complex routings")
,MSG_U(I_COMPLEXROUTES
,"You can setup multiple complex routing for email\n"
"The key is the destination, including the user name\n")
,help_cplx
,nof
,MENUBUT_ADD);
if (code == MENU_QUIT || code == MENU_ESCAPE){
break;
}else if (code == MENU_OK){
if (nof >=0 && nof < n){
COMPLEX_ROUTE *cp = getitem(nof);
int status = cp->edit();
if (status==1){
remove_del(cp);
}else if (status == 0){
save();
ret = 1;
}
}
}else if (code == MENU_ADD){
COMPLEX_ROUTE *cp = new COMPLEX_ROUTE;
if (cp->edit()==0){
add (cp);
save();
ret = 1;
}else{
delete cp;
}
}
}
return ret;
}
/*
Return != 0 if some entry were modified
*/
int complex_edit ()
{
COMPLEX_ROUTES cpl;
return cpl.edit();
}
/*
Split and validate an addres of the form user@domain
*/
static int complex_parse (
const SSTRING &adr,
char *user,
char *site)
{
int ret = -1;
char buf[200];
adr.copy (buf);
user[0] = site[0] = '\0';
char *pt = strchr (buf,'@');
if (pt != NULL){
*pt++ = '\0';
strcpy (user,buf);
strcpy (site,pt);
ret = 0;
}
return ret;
}
/*
Generate the rules to be insert in the ruleset 0 of sendmail.cf.
if fout == NULL, this function is simply called to validate the
rule.
*/
PUBLIC int COMPLEX_ROUTE::rule0(FILE *fout, char *status)
{
/* #Specification: mailconf / complex user routing / inactive
An inactive rule is not validated. This means the user may
left a rules half finished.
*/
int ret = 0;
status[0] = '\0';
if (active){
ret = 0;
char userto[200],siteto[200];
userto[0] = siteto[0] = '\0';
if (to.is_empty()){
status += sprintf (status
,MSG_U(F_NOEMPTY,"Field \"%s\" can't be empty\n")
,MSG_R(F_TO));
ret = -1;
}else if (complex_parse (to,userto,siteto) == -1){
ret = -1;
status += sprintf (status
,MSG_U(F_IVLDTO,"Field \"%s\" is invalid or incomplete\n"
" Was expecting user@domain format\n")
,MSG_R(F_TO));
}
char new_userto[200],new_siteto[200];
new_userto[0] = new_siteto[0] = '\0';
int localhost = 0;
if (new_to.is_empty()){
status += sprintf (status
,MSG_R(F_NOEMPTY)
,MSG_R(F_NEWTO));
ret = -1;
}else if (new_to.strchr('@')==NULL){
/* #Specification: mailconf / complex routing / new to no site
If the "rewritten to" field only contain a name (without @)
it is taken as a local user name. This is especially useful
when hosting virtual domain and you have the setup
#
info@virtual1.com -> info1
info@virtual2.com -> joewho
#
*/
localhost = 1;
new_to.copy (new_userto);
}else if (complex_parse (new_to,new_userto,new_siteto)==-1){
ret = -1;
status += sprintf (status,MSG_R(F_IVLDTO),MSG_R(F_NEWTO));
}
char str_router[200];
if (router.is_empty()){
strcpy (str_router,new_siteto);
}else{
router.copy(str_router);
}
if (!localhost && mailer.is_empty()){
status += sprintf (status
,MSG_R(F_NOEMPTY)
,MSG_R(F_MAILER));
ret = -1;
}
if (fout != NULL && ret == 0){
char *pt = "";
// Another rule in case the domain is qualified by the dns
// and a . has been added.
for (int i=0; i<2; i++, pt = "."){
if (localhost){
fprintf (fout,"R%s<@%s%s>\t$#local $: @ %s\n"
,userto,siteto,pt
,new_userto);
}else{
fprintf (fout,"R%s<@%s%s>\t$#%s $@%s $: %s < @ %s>\n"
,userto,siteto,pt
,mailer.get(),str_router
,new_userto,new_siteto);
}
}
}
}
return ret;
}
/*
Generate the require parts of ruleset 0.
Return -1 if any errors.
*/
PUBLIC int COMPLEX_ROUTES::rule0(FILE *fout)
{
int ret = 0;
int n = getnb();
for (int i=0; i<n; i++){
COMPLEX_ROUTE *c = getitem(i);
char status[10000];
ret |= c->rule0(fout,status);
}
return ret;
}